package com.geek.novel.utils

import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.text.TextUtils
import java.io.File
import java.io.FileOutputStream
import java.net.HttpURLConnection
import java.net.URL

/**
 * 网络下载请求相关工具
 */
class DownloadUtil(private val handler: Handler) {

    /**下载速度*/
//    private val downloadSpeed = 1024
    private val downloadSpeed = 1024*10

    companion object{
        /**下载中*/
        const val DOWNLOAD_PROGRESS = 1
        /**下载完成*/
        const val DOWNLOAD_SUCCESS = 2
        /**取消下载*/
        const val CANCEL_DOWNLOAD = 3
        /**下载失败*/
        const val DOWNLOAD_ERROR = 4
        /**默认的map集合的key*/
        const val defaultKey = "default_key"
    }

    /**intent列表，用于遍历删除文件之类的操作*/
    private var intentMap = HashMap<String, Intent>()
    /**保存线程的集合*/
    private var threadMap = HashMap<String, DownApkRunnable>()

    fun cancel(key: String=defaultKey){
        val msg = Message()
        msg.what = CANCEL_DOWNLOAD
        msg.data = Bundle()
        msg.data.putString("key", key)
        handler.sendMessage(msg)
        removeKey(key)
        this.onDestroy()
    }

    fun onDestroy() {
        for (entry in intentMap) {
            this.deleteFile(entry.value)
            this.removeKey(entry.key)
        }
    }

    private fun removeKey(key: String){
        val thread = threadMap[key]
        if(thread != null){
            thread.canceled = true
        }
        threadMap.remove(key)
        intentMap.remove(key)
    }

    /**
     * 删除文件
     */
    private fun deleteFile(intent: Intent){
        val apkPath = intent.getStringExtra("path")
        val apkName = intent.getStringExtra("name")
        val apkFile = File(apkPath, apkName!!)
        if (apkFile.exists()) {
            apkFile.delete()
        }
        val apkDownloadingFile = File(apkPath, this.getDownloadingName(apkName))
        if (apkDownloadingFile.exists()) {
            apkDownloadingFile.delete()
        }
    }

    /**获取下载中的文件的名称*/
    private fun getDownloadingName(name: String): String{
        return "${name}_downloading"
    }

    /**
     * 开启线程下载文件
     */
    internal inner class DownApkRunnable(private val intent: Intent) : Runnable {

        var canceled = false

        override fun run() {
            downloadFile(intent)
        }

        private fun downloadFile(intent: Intent) {
            val downloadUrl = intent.getStringExtra("url")
            val filePath = intent.getStringExtra("path")
            val fileName = intent.getStringExtra("name")
            val key = intent.getStringExtra("key")?:defaultKey

            val bundle = Bundle()
            bundle.putString("url", downloadUrl)
            bundle.putString("path", filePath)
            bundle.putString("name", fileName)
            bundle.putString("key", key)

            canceled = false
            var conn: HttpURLConnection? = null
            try {
                if (TextUtils.isEmpty(downloadUrl)) {
                    throw Exception("下载url不能为空")
                }
                val url = URL(downloadUrl)
                conn = url.openConnection() as HttpURLConnection
                conn.connectTimeout = 3 * 1000
                conn.requestMethod = "GET"
                conn.setRequestProperty(
                    "Accept",
                    "image/gif, image/jpeg, image/pjpeg, image/pjpeg, " +
                            "application/x-shockwave-flash, application/xaml+xml, " +
                            "application/vnd.ms-xpsdocument, application/x-ms-xbap, " +
                            "application/x-ms-application, application/vnd.ms-excel, " +
                            "application/vnd.ms-powerpoint, application/msword, */*")
                conn.setRequestProperty("Accept-Language", "zh-CN")
                conn.setRequestProperty("Charset", "UTF-8")
                //设置浏览器类型和版本、操作系统，使用语言等信息
                conn.setRequestProperty(
                    "User-Agent",
                    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; Trident/4.0; " +
                            ".NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; " +
                            ".NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)")
                //设置为长连接
                conn.setRequestProperty("Connection", "Keep-Alive")

                val code = conn.responseCode
                if (code == HttpURLConnection.HTTP_OK) {
                    val length = conn.contentLength
                    var count = 0
                    val pathFile = File(filePath!!)
                    if (!pathFile.exists()) {
                        pathFile.mkdirs()
                    }
                    val file = File(filePath, getDownloadingName(fileName!!))
                    if(file.exists()){
                        file.delete()
                    }
                    val inputStream = conn.inputStream
                    val outputStream = FileOutputStream(file)
                    val buffer = ByteArray(downloadSpeed)
                    var lateRate = -1
                    do {
                        val numRead = inputStream.read(buffer)
                        if (numRead <= 0) {// 下载完毕
                            val msg = Message()
                            msg.data = bundle

                            val realFile = File(filePath, fileName)
                            //重命名文件
                            val renameTo = file.renameTo(realFile)
                            if(renameTo){
                                msg.what = DOWNLOAD_SUCCESS
                            }else{
                                msg.what = DOWNLOAD_ERROR
                                msg.obj = Exception("下载完成，但重命名文件失败: $code")
                            }
                            handler.sendMessage(msg)
                            canceled = true
                            break
                        }
                        count += numRead
                        val progress = (count.toFloat() / length * 100).toInt()// 得到当前进度
                        LogCatUtil.i(DownloadUtil::class.simpleName!!, "下载进度(${key}): $progress")
                        if (progress >= lateRate + 1) {// 只有当前进度比上一次进度大于等于1，才可以更新进度
                            lateRate = progress
                            val msg = Message()
                            msg.data = bundle
                            msg.what = DOWNLOAD_PROGRESS
                            msg.arg1 = progress
                            handler.sendMessage(msg)
                        }
                        outputStream.write(buffer, 0, numRead)
                    } while (!canceled)// 如果没有被取消
                    inputStream.close()
                    outputStream.close()
                } else {
                    canceled = true
                    val msg = Message()
                    msg.data = bundle
                    msg.what = DOWNLOAD_ERROR
                    msg.obj = Exception("下载失败: $code")
                    handler.sendMessage(msg)
                }
            } catch (e: Exception) {
                canceled = true
                e.printStackTrace()
                val msg = Message()
                msg.data = bundle
                msg.what = DOWNLOAD_ERROR
                msg.obj = e
                handler.sendMessage(msg)
            } finally {
                removeKey(key)
                conn?.disconnect()
            }

        }

    }

    /**开始下载*/
    fun startDownload(intent: Intent){
        val key = intent.getStringExtra("key")?: defaultKey
        if(intentMap[key] == null){
            intentMap[key] = intent
            val downApkRunnable = DownApkRunnable(intent)
            threadMap[key] = downApkRunnable
            Thread(downApkRunnable).start()
        }
    }

}